#include <panel.h>
#include "level.h"
#include "actor.h"
#include "tile.h"
#include "game.h"
#include "extras.h"

extern Actor Player,LoadedActor[NUM_ACTORS];
extern Tile LoadedTile[];
extern WINDOW* mapwin;
extern PANEL* mappan;
extern GameInfo Game;

Level::Level(){
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			tilemap[i][j]=NULL;
			actormap[i][j]=NULL;
		}
	}
}
void Level::Clear(){
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			if(actormap[i][j]!=NULL){
				if(actormap[i][j]->IsAllied()){
					if(actormap[i][j]!=&Player){
						actormap[i][j]->Unsummon();
					}					actormap[i][j] = NULL;
				}
				else{
					actormap[i][j]->RFG();
				}
			}
			if(tilemap[i][j]!=NULL){
				tilemap[i][j]->RFG();
			}
			wmove(mapwin,i,j);
			waddch(mapwin,' ');
		}
	}
}
bool Level::Generate(LevelType type){
	char tile[ROWS][COLS];
	if(type!=TOWN){
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			tile[i][j]='#';
		}
	}
	int rr1=Roll(1,6)+7;
	int rc1=Roll(1,26)+19;
	int h1=Roll(1,4)+2;
	int w1=Roll(1,5)+3;
	for(int i=rr1;i<rr1+h1;++i){
		for(int j=rc1;j<rc1+w1;++j){
			tile[i][j]='.';
		}
	}
	for(int s=0;s<400;++s){
		int rr,rc;
		bool found=false;
		for(int i=0;i<99999 && !found;++i){
			rr=Roll(1,ROWS-4);
			rc=Roll(1,COLS-5);
			if(tile[rr][rc]=='#'){
				int total=0;
				if(tile[rr-1][rc]=='.'){
					++total;
				}
				if(tile[rr+1][rc]=='.'){
					++total;
				}
				if(tile[rr][rc-1]=='.'){
					++total;
				}
				if(tile[rr][rc+1]=='.'){
					++total;
				}
				if(total==1){
					found=true;
				}
			}
		}
		if(found){
			int dir;
			if(tile[rr-1][rc]=='.'){
				dir=8;
			}
			else{
				if(tile[rr+1][rc]=='.'){
					dir=2;
				}
				else{
					if(tile[rr][rc-1]=='.'){
						dir=4;
					}
					else{
						if(tile[rr][rc+1]=='.'){
							dir=6;
						}
					}
				}
			}
			bool room=false;
			switch(dir){
				case 8:
					if(tile[rr-2][rc]=='.'){
						if(tile[rr-2][rc-1]=='.' && tile[rr-1][rc-1]=='.'){
							room=true;
						}
						else{
							if(tile[rr-2][rc+1]=='.' && tile[rr-1][rc+1]=='.'){
								room=true;
							}
						}
					}
					break;
				case 6:
					if(tile[rr][rc+2]=='.'){
						if(tile[rr-1][rc+2]=='.' && tile[rr-1][rc+1]=='.'){
							room=true;
						}
						else{
							if(tile[rr+1][rc+2]=='.' && tile[rr+1][rc+1]=='.'){
								room=true;
							}
						}
					}
					break;
				case 2:
					if(tile[rr+2][rc]=='.'){
						if(tile[rr+2][rc+1]=='.' && tile[rr+1][rc+1]=='.'){
							room=true;
						}
						else{
							if(tile[rr+2][rc-1]=='.' && tile[rr+1][rc-1]=='.'){
								room=true;
							}
						}
					}
					break;
				case 4:
					if(tile[rr][rc-2]=='.'){
						if(tile[rr+1][rc-2]=='.' && tile[rr+1][rc-1]=='.'){
							room=true;
						}
						else{
							if(tile[rr-1][rc-2]=='.' && tile[rr-1][rc-1]=='.'){
								room=true;
							}
						}
					}
					break;
			}
			int dif=0;
			if(room){
				dif=3;
			}
			if(Roll(1,10)+dif<=4){ //room
				int h=Roll(1,4)+2;
				int w=Roll(1,5)+3;
				int offset=0;
				if(dir==8 || dir==2){
					if(w%2==0 && Roll(1,2)==1){
						offset=1;
					}
				}
				else{
					if(h%2==0 && Roll(1,2)==1){
						offset=1;
					}
				}
				int corner_r,corner_c;
				switch(dir){
					case 8:
						corner_r=rr+1;
						corner_c=rc-(w/2)+offset;
						break;
					case 6:
						corner_r=rr-(h/2)+offset;
						corner_c=rc-w;
						break;
					case 2:
						corner_r=rr-h;
						corner_c=rc-(w/2)+offset;
						break;
					case 4:
						corner_r=rr-(h/2)+offset;
						corner_c=rc+1;
						break;
				}
				bool good=true;
				for(int i=corner_r-1;i<=corner_r+h && good;++i){
					for(int j=corner_c-1;j<=corner_c+w && good;++j){
						if(i<0 || j<0 || i>ROWS-1 || j>COLS-1 || tile[i][j]!='#'){
							good=false;
						}
					}
				}
				if(good){
					for(int i=corner_r;i<corner_r+h;++i){
						for(int j=corner_c;j<corner_c+w;++j){
							tile[i][j]='.';
						}
					}
					tile[rr][rc]='.';
				}
			}
			else{ //corridor
				int length=Roll(1,6)+3;
				int start_r=rr,start_c=rc;
				int h=1, w=1;
				switch(dir){
					case 8:
						++start_r;
						h=length;
						break;
					case 6:
						start_c-=length;
						w=length;
						break;
					case 2:
						start_r-=length;
						h=length;
						break;
					case 4:
						++start_c;
						w=length;
						break;
				}
				bool good=true;
				for(int i=start_r-1;i<=start_r+h && good;++i){
					for(int j=start_c-1;j<=start_c+w && good;++j){
						if(i<0 || j<0 || i>ROWS-1 || j>COLS-1 || tile[i][j]!='#'){
							good=false;
						}
					}
				}
				if(good){
					for(int i=start_r;i<start_r+h;++i){
						for(int j=start_c;j<start_c+w;++j){
							tile[i][j]='.';
						}
					}
					tile[rr][rc]='.';
				}
			}
		}
		if(s==199 || s==399){
			bool done=false;
			while(!done){
				done=true;
				for(int i=0;i<ROWS;++i){
					for(int j=0;j<COLS;++j){
						if(tile[i][j]=='.' || tile[i][j]=='+'){
							int total=0;
							if(tile[i-1][j]=='#'){
								++total;
							}
							if(tile[i+1][j]=='#'){
								++total;
							}
							if(tile[i][j-1]=='#'){
								++total;
							}
							if(tile[i][j+1]=='#'){
								++total;
							}
							if(total >= 3){
								tile[i][j]='#';
								done=false;
							}
						}
					}
				}
			}
		}
	}
	if(type==FOREST_1){ //left side
		for(int i=10;i<=11;++i){
			for(int j=0;j<5;++j){
				tile[i][j]='.';
			}
		}
	}
	if(type==FOREST_1 || type==FOREST_2){ //right side
		for(int i=10;i<=11;++i){
			for(int j=61;j<66;++j){
				tile[i][j]='.';
			}
		}
	}
	for(int times=0;times<7;++times){
		for(int i=0;i<ROWS;++i){
			for(int j=0;j<COLS;++j){
				if(tile[i][j]=='.'){
					int total = 0;
					if(tile[i-1][j]=='#'){
						++total;
					}
					if(tile[i+1][j]=='#'){
						++total;
					}
					if(tile[i][j-1]=='#'){
						++total;
					}
					if(tile[i][j+1]=='#'){
						++total;
					}
					if(total >= 2){
						if(Roll(1,5)==5){
							for(int s=i-1;s<=i+1;++s){
								for(int t=j-1;t<=j+1;++t){
									if(s>=1 && s<ROWS-1 && t>=1 && t<COLS-1){
										tile[s][t] = '.';
									}
								}
							}
						}
						else{
							if(Roll(1,2)==2){
								if(i>=1 && i<ROWS-1 && j>=1 && j<COLS-1){
									tile[i][j] = '#';
								}
							}
						}
					}
				}
			}
		}
	}
	}
	else{ //if TOWN
		for(int i=0;i<ROWS;++i){
			for(int j=0;j<COLS;++j){
				tile[i][j]='.';
			}
		}
		bool done=false;
		while(!done){ //shop
			int rr = Roll(1,ROWS-5);
			int rc = Roll(1,COLS-5);
			int h = 2 + Roll(1,4);
			int w = 3 + Roll(1,6);
			bool good=true;
			for(int i=rr-1;i<rr+h+1;++i){
				for(int j=rc-1;j<rc+w+1;++j){
					if(tile[i][j]!='.' || i<0 || i>=ROWS || j<0 || j>=COLS){
						good=false;
					}
				}
			}
			if(good){
				done=true;
				for(int i=rr;i<rr+h;++i){
					for(int j=rc;j<rc+w;++j){
						if(i==rr || j==rc || i==rr+h-1 || j==rc+w-1){
							tile[i][j]='#';
						}
					}
				}
				tile[rr+1][rc]='.';
				tile[rr+h-2][rc+w-2]='S';
			}
		}
		done=false;
		while(!done){ //library
			int rr = Roll(1,ROWS-5);
			int rc = Roll(1,COLS-5);
			int h = 4 + Roll(1,4);
			int w = 6 + Roll(1,6);
			bool good=true;
			for(int i=rr-1;i<rr+h+1;++i){
				for(int j=rc-1;j<rc+w+1;++j){
					if(tile[i][j]!='.' || i<0 || i>=ROWS || j<0 || j>=COLS){
						good=false;
					}
				}
			}
			if(good){
				done=true;
				for(int i=rr;i<rr+h;++i){
					for(int j=rc;j<rc+w;++j){
						if(i==rr || j==rc || i==rr+h-1 || j==rc+w-1){
							tile[i][j]='#';
						}
					}
				}
				tile[rr][rc+(w/2)]='.';
				tile[rr+(h/2)][rc+(w/2)]='L';
			}
		}
		for(int count=0;count<12;++count){
			int rr = Roll(1,ROWS-5);
			int rc = Roll(1,COLS-5);
			int h = 2 + Roll(1,4);
			int w = 2 + Roll(1,6);
			bool good=true;
			for(int i=rr-1;i<rr+h+1;++i){
				for(int j=rc-1;j<rc+w+1;++j){
					if(tile[i][j]!='.' || i<0 || i>=ROWS || j<0 || j>=COLS){
						good=false;
					}
				}
			}
			if(good){
				for(int i=rr;i<rr+h;++i){
					for(int j=rc;j<rc+w;++j){
						tile[i][j]='#';
					}
				}
			}
		}
	}
	for(int i=0;i<ROWS;++i){
		if(type!=FOREST_1){
			tile[i][0] = '#';
		}
		if(type==TOWN && (i==10 || i==11)){
			tile[i][0] = '.';
		}
		if(type!=FOREST_1 && type!=FOREST_2){
			tile[i][COLS-1] = '#';
		}
	}
	for(int j=0;j<COLS;++j){
		tile[0][j] = '#';
		tile[ROWS-1][j] = '#';
	}
	if(type!=TOWN){
		bool marked=false;
		bool changed=true;
		for(int i=0;i<ROWS && !marked;++i){
			for(int j=0;j<COLS && !marked;++j){
				if(tile[i][j] == '.'){
					tile[i][j] = 'a';
					marked=true;
				}
			}
		}
		while(changed){
			changed=false;
			for(int i=0;i<ROWS;++i){
				for(int j=0;j<COLS;++j){
					if(tile[i][j] == 'a'){
						if(tile[i-1][j-1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i-1][j-1]='a'; changed=true;}
						if(tile[i-1][j+1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i-1][j+1]='a'; changed=true; }
						if(tile[i+1][j-1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i+1][j-1]='a'; changed=true; }
						if(tile[i+1][j+1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i+1][j+1]='a'; changed=true; }
						if(tile[i][j-1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i][j-1]='a'; changed=true; }
						if(tile[i][j+1]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i][j+1]='a'; changed=true; }
						if(tile[i-1][j]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i-1][j]='a'; changed=true; }
						if(tile[i+1][j]=='.' && i>=0 && i<ROWS && j>=0 && j<COLS){ tile[i+1][j]='a'; changed=true; }
					}
				}
			}
		}
		marked=false;
		changed=true;
		for(int i=0;i<ROWS && !marked;++i){
			for(int j=0;j<COLS && !marked;++j){
				if(tile[i][j] == '.'){
					tile[i][j] = 'b';
					marked=true;
				}
			}
		}
		while(changed){
			changed=false;
			for(int i=0;i<ROWS;++i){
				for(int j=0;j<COLS;++j){
					if(tile[i][j] == 'b'){
						if(tile[i-1][j-1]=='.'){ tile[i-1][j-1]='b'; changed=true; }
						if(tile[i-1][j+1]=='.'){ tile[i-1][j+1]='b'; changed=true; }
						if(tile[i+1][j-1]=='.'){ tile[i+1][j-1]='b'; changed=true; }
						if(tile[i+1][j+1]=='.'){ tile[i+1][j+1]='b'; changed=true; }
						if(tile[i][j-1]=='.'){ tile[i][j-1]='b'; changed=true; }
						if(tile[i][j+1]=='.'){ tile[i][j+1]='b'; changed=true; }
						if(tile[i-1][j]=='.'){ tile[i-1][j]='b'; changed=true; }
						if(tile[i+1][j]=='.'){ tile[i+1][j]='b'; changed=true; }
					}
				}
			}
		}
		for(int i=0;i<ROWS;++i){
			for(int j=0;j<COLS;++j){
				if(tile[i][j]=='b'){
					return false;
				}
			}
		}
		for(int i=0;i<ROWS;++i){
			for(int j=0;j<COLS;++j){
				if(tile[i][j]>='a' && tile[i][j]<='z'){
					tile[i][j]='.';
				}
			}
		}
	}
	bool done=false;
	int st_r,st_c;
	while(!done && (type==FOREST_2 || type==CAVE_1 || type==CAVE_2)){
		int rr=Roll(1,ROWS-4)+1;
		int rc=Roll(1,COLS-4)+1;
		if(tile[rr][rc]=='.'){
			done=true;
			for(int i=rr-1;i<=rr+1;++i){
				for(int j=rc-1;j<=rc+1;++j){
					if(tile[i][j]!='.'){
						done=false;
					}
				}
			}
			if(done){
				tile[rr][rc]='>';
				st_r=rr;
				st_c=rc;
			}
		}
	}
	done=false;
	int what = 100;
	while(!done && (type==CAVE_3 || type==CAVE_2 || type==CAVE_1)){
		int rr=Roll(1,ROWS-4)+1;
		int rc=Roll(1,COLS-4)+1;
		if(tile[rr][rc]=='.' && abs(st_r - rr)>(3*what)/100 && abs(st_c - rc)>(8*what)/100){ //crazy way to prevent tiny level freezes
			done=true;
			for(int i=rr-1;i<=rr+1;++i){
				for(int j=rc-1;j<=rc+1;++j){
					if(tile[i][j]!='.'){
						done=false;
					}
				}
			}
			if(done){
				tile[rr][rc]='<';
			}
		}
		--what;
	}
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			switch(tile[i][j]){
				case '.':
					if(type == FOREST_1 || type == FOREST_2){
					LoadedTile[6].CloneSelf(i,j);
					}
					else{
					LoadedTile[0].CloneSelf(i,j);
					}
					break;
				case '#':
					if(type == FOREST_1 || type == FOREST_2){
					LoadedTile[5].CloneSelf(i,j);
					}
					else{
					LoadedTile[1].CloneSelf(i,j);
					}
					break;
				case '-':
					LoadedTile[2].CloneSelf(i,j);
					break;
				case '+':
					LoadedTile[3].CloneSelf(i,j);
					break;
				case '>':
					LoadedTile[4].CloneSelf(i,j);
					break;
				case '<':
					LoadedTile[7].CloneSelf(i,j);
					break;
				case 'S':
					LoadedTile[0].CloneSelf(i,j);
					LoadedActor[17].CloneSelf(i,j);
					break;
				case 'L':
					LoadedTile[0].CloneSelf(i,j);
					LoadedActor[16].CloneSelf(i,j);
					break;
				default:
					LoadedTile[0].CloneSelf(i,j);
					break;
			}
		}
	}
	return true;
}
void Level::Draw(){
/*	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			tilemap[i][j]->Draw(true,true);
		}
	}*/
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			if(Player.CanSee(i,j)){
				if(ActorPtr(i,j)!=NULL && Player.CanSee(ActorPtr(i,j))){
					TilePtr(i,j)->MarkAsSeen();
					ActorPtr(i,j)->Draw();
				}
				else{
					if(TilePtr(i,j)->ItemPtr()!=NULL){
						TilePtr(i,j)->MarkAsSeen();
						TilePtr(i,j)->ItemPtr()->Draw();
					}
					else{
						if(Game.CurrentLevel()==TOWN){
							TilePtr(i,j)->Draw(true,true);
						}
						else{
							if(TilePtr(i,j)->IsOpaque()){
								TilePtr(i,j)->Draw(true,TilePtr(i,j)->OpaqueIsLit(Player.Row(),Player.Col()));
							}
							else{
								TilePtr(i,j)->Draw(true,TilePtr(i,j)->IsLit());
							}
						}
					}
				}
			}
			else{
				if(TilePtr(i,j)->HasBeenSeen()){
					TilePtr(i,j)->Draw(false,false);
				}
				else{
					wmove(mapwin,i,j);
					waddch(mapwin,' ');
				}
			}
		}
	}
}
void Level::RemoveTargets(Actor* ptr){
	for(int i=0;i<ROWS;++i){
		for(int j=0;j<COLS;++j){
			if(actormap[i][j]!=NULL){
				actormap[i][j]->RemoveTarget(ptr);
			}
		}
	}
}

